package l1j.server.server.clientpackets;

import static l1j.server.server.model.Instance.L1PcInstance.REGENSTATE_MOVE;
import static l1j.server.server.model.skill.L1SkillId.ABSOLUTE_BARRIER;
import static l1j.server.server.model.skill.L1SkillId.MEDITATION;


import l1j.opqlo.Server.L1World.L1World;
import l1j.server.GameServer.GameServer;
import l1j.server.echo.ClientThread;
import l1j.server.server.IdFactory;
import l1j.server.server.datatables.NpcTable;
import l1j.server.server.model.Dungeon;
import l1j.server.server.model.DungeonRandom;
import l1j.server.server.model.L1Location;
import l1j.server.server.model.L1Teleport;
import l1j.server.server.model.Instance.L1NpcInstance;
import l1j.server.server.model.Instance.L1PcInstance;
import l1j.server.server.model.map.L1Map;
import l1j.server.server.model.trap.L1WorldTraps;
import l1j.server.server.serverpackets.S_MoveCharPacket;
import l1j.server.server.types.Point;

import java.util.logging.Level;
import java.util.logging.Logger;

public class C_MoveChar extends ClientBasePacketOld {

	//	private static final Logger _log = Logger.getLogger(C_MoveChar.class.getName());

	private static final byte HEADING_TABLE_X[] =
		{ 0, 1, 1, 1, 0, -1, -1, -1 };

	private static final byte HEADING_TABLE_Y[] =
		{ -1, -1, 0, 1, 1, 1, 0, -1 };
	/*
	@Override
	public void start(final byte[] decrypt, final ClientThread client) {
		try {
			// 資料載入
			read(decrypt);*/
	private static final Logger _log = Logger.getLogger(C_MoveChar.class.getName());

	public C_MoveChar(byte decrypt[], ClientThread client) throws Exception {
		super(decrypt);
		try {
			final L1PcInstance pc = client.getActiveChar();

			if (pc==null || pc.isGhost() || pc.isDead() || pc.isTeleport() || pc.getSuper()>0|| pc.isParalyzed() || pc.isSleeped()) {//opqlo 掛機檢測
				return;
			}
			if(pc._inFighting ==1 || pc._inFighting==3){
				return;
			}
			int locx = pc.getX();//物件X
			int locy = pc.getY();//物件Y
			final int loc_X = this.readH();//封包X
			final int loc_Y = this.readH();//封包Y
			int heading = this.readC();

			final L1Location loc = pc.getLocation();

			if( loc_X != locx || loc_Y != locy){ //如果Client端物件座標錯位
				L1Teleport.teleportByMagic(pc , loc.getX() , loc.getY() , (short) loc.getMapId(), heading , false);
				return;
			}


			// TODO 角色XY軸修正
			if (heading > 8) { // Taiwan Only
				heading ^= 0x49;
			}
			locx += HEADING_TABLE_X[heading];
			locy += HEADING_TABLE_Y[heading];


			final L1Map map = loc.getMap();
			if (Dungeon.getInstance().dg(locx, locy, map.getId(), pc)) { // ダンジョンにテレポートした場合
				return;
			}
			if (DungeonRandom.getInstance().dg(locx, locy, map.getId(), pc)) { // テレポート先がランダムなテレポート地点
				return;
			}
			/**opqlo 防穿人*/
			if(L1World.getInstance().isHasObjects(map,new Point(locx,locy))){
				L1Teleport.teleportByMagic(pc , loc.getX() , loc.getY() , (short) map.getId(), heading , false);
				return;
			}
			if(map.isExistDoor(locx, locy) == 0x03) {
				L1Teleport.teleportByMagic(pc , loc.getX() , loc.getY() , (short) map.getId(), heading , false);
				return;
			}
			/**opqlo 防穿牆*/
			if(!map.isPassableAllHeading(locx , locy)){
				final L1Location location =new L1Location(locx,locy , map);
				L1Teleport.teleportByMagic(pc , loc.getX() , loc.getY() , (short) map.getId(), heading , false);
				pc.addMoveErrorCount(loc);
				GameServer.getInstance().addLogMob(location);
				try {
					final L1NpcInstance npc = NpcTable.getInstance().newNpcInstance(710049);
					npc.setId(IdFactory.getInstance().nextId());
					npc.setMap(location.getMap());
					npc.getLocation().set(location);
					npc.setHomeX(npc.getX());
					npc.setHomeY(npc.getY());
					npc.setHeading(0);
					L1World.getInstance().storeObject(npc);
					L1World.getInstance().addVisibleObject(npc);
				} catch (final Exception e) {
					_log.log(Level.SEVERE, e.getLocalizedMessage(), e);
				}
				return;
			}
			/*
			if(!map.isPassable(locx, locy)
					&& L1World.getInstance().getVisibleObjects(pc, 1).size()<8
					&& map.isPassableAllHeading(locx, locy)
			){
				pc.sendPackets(new S_OwnCharPack(pc));
				pc.removeAllKnownObjects();
				pc.updateObject();
				pc.sendVisualEffectAtTeleport(); // クラウン、毒、水中等の視覚効果を表示
				pc.sendPackets(new S_CharVisualUpdate(pc));
				pc.addMoveErrorCount();
				return;

			}
			if((!map.isPassable(pc.getX() , pc.getY() , pc.getHeading())) && map.isPassable(pc.getX() , pc.getY()) ){
			//	spawn(map.getId() , locx,locy);
				pc.sendPackets(new S_OwnCharPack(pc));
				pc.removeAllKnownObjects();
				pc.updateObject();
				pc.sendVisualEffectAtTeleport(); // クラウン、毒、水中等の視覚効果を表示
				pc.sendPackets(new S_CharVisualUpdate(pc));
				pc.addMoveErrorCount();
				return;
			}


			//修正穿人bug by eric1300460
			/*		for(final L1Object object : L1World.getInstance().getVisibleObjects(pc, 0)){
					if(object==null){continue;}
					if(!(object instanceof L1Character)){continue;}
					/*	if(object != null && object instanceof L1Character	//opqlo 修正穿人寫法
			&& !(object instanceof L1DollInstance)
			&& !(object instanceof L1DoorInstance)
			&& !(object instanceof L1EffectInstance)
			&& !(object instanceof L1FieldObjectInstance)
			){*/
			/*	final L1Character cha = (L1Character) object;
					if(cha.isDead()){break;}
					if(cha instanceof L1PcInstance ){
						L1PcInstance pc =(L1PcInstance) cha;
						if (pc.isGmInvis() || pc.isGhost()|| pc.hasSkillEffect(INVISIBILITY)) {break;}//opqlo 修正穿人寫法
						L1Teleport.teleport(pc, pc.getLastLocation(), pc.getHeading(), true); // 回到前一點
						return;
					}
					if( cha instanceof L1MonsterInstance){
						L1Teleport.teleport(pc, pc.getLastLocation(), pc.getHeading(), true); // 回到前一點
						return;
					}
					if (cha instanceof L1FieldObjectInstance){
						L1Teleport.teleport(pc, pc.getLastLocation(), pc.getHeading(), true); // 回到前一點
						return;
					}
				}
			 */
			// 移動要求間隔をチェックする
			final int result =pc.getAcceleratorChecker().checkInterval(AcceleratorChecker.ACT_TYPE.MOVE);
			if (result == AcceleratorChecker.R_DISCONNECTED) {
				L1Teleport.teleportByMagic(pc , loc.getX() , loc.getY() , (short) loc.getMapId(), heading , false);
				return;
			}

			map.setPassable(loc, true);
			pc.setLastLocation(loc);
			loc.set(locx, locy);
			pc.setHeading(heading);
			//pc.setLastLocation(new L1Location(pc.getLocation()));


			if(pc.isGmInvis() || pc.isGhost()){

			}else if (pc.isInvisble()) {
				pc.broadcastPacketForFindInvis(new S_MoveCharPacket(pc), true);
			} else {
				pc.broadcastPacketAll(new S_MoveCharPacket(pc));
			}

			// sendMapTileLog(pc); // 移動先タイルの情報を送る(マップ調査用)

			// 踩到陷阱的處理
			L1WorldTraps.getInstance().onPlayerMoved(pc);

			// 新增座標障礙宣告
			map.setPassable(loc, false);


			if (pc.hasSkillEffect(MEDITATION)) { // 取消冥想效果
				pc.removeSkillEffect(MEDITATION);
			}
			pc.setCallClanId(0); // コールクランを唱えた後に移動すると召喚無効

			if (!pc.hasSkillEffect(ABSOLUTE_BARRIER)) { // アブソルートバリア中ではない
				pc.setRegenState(REGENSTATE_MOVE);
			}

		} catch (final Exception e) {
			_log.log(Level.SEVERE, e.getLocalizedMessage(), e);
		}
	}

	@Override
	public String getType() {
		return this.getClass().getSimpleName();
	}
}